import functools
import threading
from typing import List, Dict

from emi import report
from emi.core.App import App
from emi.core.Runner import RunnerContext
from emi.core.task import Task, TaskStatus


class BatchTask(Task):
    """
    批量Task的运行,需要开启Loop线程
    """
    def __init__(self,app:App,name:str,tasks:List[Task]):
        self._name = name
        self._tasks = tasks
        self._app = app
        self._condition = threading.Condition()
        self._task_running_status:Dict[str,bool]= {}
        self.last_run_time_second: float = None  ## 上次执行所花费的时间。

    def get_name(self):
        return self._name

    def on_task_changed(self,task:Task):
        if self._task_running_status.__contains__(task.id):
            self._task_running_status[task.id] = task.status.is_run()
        if self.is_all_task_finished():
            self._condition.acquire()
            self._condition.notify()  ## 唤醒线程
            self._condition.release()

        ##print(f" all_runing: {self.is_all_task_finished()}")

    def _run(self,context:RunnerContext):
        task_manager = self._app.getTaskManager()
        _time_event = report.start_time_event("任务执行耗时")
        task_manager.add_task_changed_listener(self)
        for i in range(0,len(self._tasks)):
            sub_task = self._tasks[i]
            ### 准备执行
            self._task_running_status[sub_task.id] = True
            task_manager._set_task_status(sub_task,TaskStatus.Ready_Run)
            assert sub_task.status.is_run()

        self._run_sub_task_at(0)

        ### 当其他子task完成。
        while not self.is_all_task_finished():
            self._condition.acquire()
            self._condition.wait()  ## 挂起等待被通知进行执行
            self._condition.release()

        task_manager.remove_task_changed_listener(self)

        self.last_run_time_second = _time_event.get_duration()

    def is_all_task_finished(self):
        all_finished = True
        for sub_task in self._tasks:
            if self._task_running_status[sub_task.id] is True:
                all_finished = False
                break
        return all_finished


    def _run_sub_task_at(self,index):
        if index >= len(self._tasks):
            return
        sub_task = self._tasks[index]
        task_manager = self._app.getTaskManager()
        task_manager.run_task(sub_task,on_finish_in_loop=functools.partial(self._run_sub_task_at,index+1))
